package com.css.fxfzfxqh.modules.synthesis.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.css.fxfzfxqh.constants.LevelConstants;
import com.css.fxfzfxqh.modules.buildings.calculationTasks.entity.CalculationTasks;
import com.css.fxfzfxqh.modules.buildings.calculationTasks.repository.CalculationTasksRepository;
import com.css.fxfzfxqh.modules.buildings.definitiveEvaluation.casualtiesDE.vo.ExportVO;
import com.css.fxfzfxqh.modules.buildings.definitiveEvaluation.resistEarthquakesDE.vo.ResistEarthquakesPCCVO;
import com.css.fxfzfxqh.modules.buildings.probabilityEvaluation.publicOperate.service.PublicOperateService;
import com.css.fxfzfxqh.modules.comprehensiveRiskZoneSet.model.entity.FxqhComprehensiveRiskZoneSetSet;
import com.css.fxfzfxqh.modules.singleIndexRiskZoning.vo.QhSingleExportVO;
import com.css.fxfzfxqh.modules.synthesis.entity.GDPData;
import com.css.fxfzfxqh.modules.synthesis.entity.PopulationAndLoss;
import com.css.fxfzfxqh.modules.synthesis.entity.SetUp;
import com.css.fxfzfxqh.modules.synthesis.param.CheckParam;
import com.css.fxfzfxqh.modules.synthesis.param.QhSynthesisExportParam;
import com.css.fxfzfxqh.modules.synthesis.param.QueryParam;
import com.css.fxfzfxqh.modules.synthesis.param.StatisticsParam;
import com.css.fxfzfxqh.modules.synthesis.repository.AssessRepository;
import com.css.fxfzfxqh.modules.synthesis.service.AssessService;
import com.css.fxfzfxqh.modules.synthesis.vo.QhSynthesisExportVO;
import com.css.fxfzfxqh.modules.util.ExcelUtil;
import com.css.fxfzfxqh.util.*;
import lombok.extern.slf4j.Slf4j;
import org.slw.common.helper.PropsHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AssessServiceImpl implements AssessService {
    @Autowired
    private CalculationTasksRepository calculationTasksRepository;
    @Autowired
    private AssessRepository assessRepository;
    @Autowired
    private PublicOperateService publicOperateService;
    @Autowired
    private RestTemplateUtil restTemplateUtil;

    @Override
    public Boolean check(CheckParam param) {
        if ("0".equals(param.getAssessType())) {             //确定评估
            //当前任务人口是否进行评估 true已评估 false未评估
            Boolean check1 = assessRepository.checkData1(param);
            if (!check1) return false;
            //当前任务经济是否进行评估
            Boolean check2 = assessRepository.checkData2(param);
            if (!check2) return false;
        }
        if ("1".equals(param.getAssessType())) {              //概率评估
            Boolean check3 = assessRepository.checkData3(param);
            if (!check3) return false;
            Boolean check4 = assessRepository.checkData4(param);
            if (!check4) return false;
        }
        return true;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void count(CheckParam param) {
        assessRepository.deleteByTaskId(param.getId(),param.getSeismicInputMode());
        List<SetUp> setUps = this.getSetUp();
        //查看每个县的经济GDP
        CalculationTasks tasks = calculationTasksRepository.findById(param.getId());
        List<GDPData> gdpDataList = getGDP(tasks.getGdpVersion());
        List<PopulationAndLoss> list = null;
        if ("0".equals(param.getAssessType())) {          //确定评估
            if ("0".equals(param.getSeismicInputMode()))  //设定烈度
                list = assessRepository.getData1(param);
            if ("1".equals(param.getSeismicInputMode()))  //四个概率水准
                list = assessRepository.getData2(param);
            if ("2".equals(param.getSeismicInputMode())) {  //地震影响场
                list = assessRepository.getData3(param);
                param.setInfluenceFieldVersion(tasks.getInfluenceFieldVersion());
            }
        }
        if ("1".equals(param.getAssessType()))            //概率评估
            list = assessRepository.getData4(param);
        handleAndSave(param, setUps, list, gdpDataList);
        //更新计算进度
        if ("0".equals(param.getAssessType())) {
            if ("0".equals(param.getSeismicInputMode())) {
                calculationTasksRepository.updateLdProgress(tasks.getId(),"综合指标区划","");
            }
            if ("1".equals(param.getSeismicInputMode())) {
                calculationTasksRepository.updateFourProbabilisticProgress(tasks.getId(),"综合指标区划","");
            }
            if ("2".equals(param.getSeismicInputMode())) {
                calculationTasksRepository.updateStructuralFieldProgress(tasks.getId(),"综合指标区划","");
            }
        }else {
            //发生
            if (tasks.getSeismicInputMode().equals("3")){
                calculationTasksRepository.updateFSProgress(tasks.getId(),"综合指标区划","");
            }
            //超越
            if (tasks.getSeismicInputMode().equals("4")){
                calculationTasksRepository.updateCYProgress(tasks.getId(),"综合指标区划","");
            }
        }
    }

    private List<GDPData> getGDP(String dataVersion) {
        Properties configGroup = PropsHelper.loadProps("slw-config.properties");
        String url = configGroup.getProperty("datacenterRestUrl") + "/fxqh/getFaults?dataVersion=" + dataVersion;
        Map<String, Object> paramMap = new HashMap<>();
        ResponseEntity<String> cchResponseEntity = restTemplateUtil.sendHttpRequest(url, paramMap);
        List<GDPData> gdpData = JSONObject.parseArray(cchResponseEntity.getBody(), GDPData.class);
        return gdpData;
    }

    @Override
    public Map<String, Object> getResults(QueryParam param, int page, int size) {
        Map<String, Object> map = assessRepository.getResults(param, page, size);
        return map;
    }

    @Override
    public List<StatisticsParam> statistics(QueryParam param) {
        return assessRepository.statistics(param);

    }

    private void handleAndSave(CheckParam param, List<SetUp> setUps, List<PopulationAndLoss> list, List<GDPData> gdpDataList) {
        for (PopulationAndLoss populationAndLoss : list) {
            if ("2".equals(param.getSeismicInputMode())){
                populationAndLoss.setType(param.getInfluenceFieldVersion());
            }
            GDPData gdpData = null;
            try {
                gdpData = gdpDataList.stream().filter(s -> populationAndLoss.getCounty().equals(s.getCounty())).collect(Collectors.toList()).get(0);
            } catch (Exception e) {
                throw new RuntimeException("计算失败,请确保当前任务经济版本能够完全覆盖任务区域");
            }
            populationAndLoss.setTotal(gdpData.getGDP());
            if (populationAndLoss.getProvince().contains("新疆") || populationAndLoss.getProvince().contains("青海") || populationAndLoss.getProvince().contains("西藏"))
                countLevel(populationAndLoss, setUps.get(1));
            else
                countLevel(populationAndLoss, setUps.get(0));
        }
        this.saveResult(list, param.getId());
    }

    private void saveResult(List<PopulationAndLoss> list, String taskId) {
        for (PopulationAndLoss populationAndLoss : list) {
            populationAndLoss.setId(UUIDGenerator.getUUID());
            populationAndLoss.setTaskId(taskId);
            populationAndLoss.setCreateUser(PlatformSessionUtils.getUserId());
            populationAndLoss.setCreateTime(PlatformDateUtils.getCurrentTimestamp());
            try {
                String geom = publicOperateService.getGeomByCode(populationAndLoss.getProvince(), populationAndLoss.getCity(), populationAndLoss.getCounty());
                populationAndLoss.setGeom(geom);
            } catch (Exception e) {
                log.error("获取空间属性失败");
            }

        }
        assessRepository.saveResult(list);
    }

    private void countLevel(PopulationAndLoss entity, SetUp setUp) {
        Double populationSum = entity.getPopulationSum();
        BigDecimal lossSum = PlatformObjectUtils.isNotEmpty(entity.getLossSum())?BigDecimal.valueOf(entity.getLossSum()):BigDecimal.ZERO;
        BigDecimal total = BigDecimal.valueOf(entity.getTotal());
        Double lossRatio = lossSum.divide(total, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).doubleValue();
        if (populationSum >= setUp.getDeathV4() || lossRatio >= setUp.getLossV4()) {
            entity.setLevel(LevelConstants.ONE_LEVEL);
            return;
        }
        if ((populationSum < setUp.getDeathV4() && populationSum >= setUp.getDeathV3()) || (lossRatio < setUp.getLossV4() && lossRatio >= setUp.getLossV3())) {
            entity.setLevel(LevelConstants.TWO_LEVEL);
            return;
        }
        if ((populationSum < setUp.getDeathV3() && populationSum >= setUp.getDeathV2()) || (lossRatio < setUp.getLossV3() && lossRatio >= setUp.getLossV2())) {
            entity.setLevel(LevelConstants.THREE_LEVEL);
            return;
        }
        if ((populationSum < setUp.getDeathV2() && populationSum >= setUp.getDeathV1()) || (lossRatio < setUp.getLossV2() && lossRatio >= setUp.getLossV1())) {
            entity.setLevel(LevelConstants.FOUR_LEVEL);
            return;
        }
        if (populationSum < setUp.getDeathV1() || lossRatio < setUp.getLossV1()) {
            entity.setLevel(LevelConstants.FIVE_LEVEL);
            return;
        }
    }

    private List<SetUp> getSetUp() {
        List<FxqhComprehensiveRiskZoneSetSet> setList = assessRepository.getSetUp();
        if (setList.size() == 0) {
            throw new RuntimeException("请先去维护综合风险区划设置数据");
        }
        SetUp setUp1 = new SetUp(Double.valueOf(setList.get(0).getV1()), Double.valueOf(setList.get(0).getV2()), Double.valueOf(setList.get(0).getV3()), Double.valueOf(setList.get(0).getV4()), Double.valueOf(setList.get(2).getV1()), Double.valueOf(setList.get(2).getV2()), Double.valueOf(setList.get(2).getV3()), Double.valueOf(setList.get(2).getV4()));
        SetUp setUp2 = new SetUp(Double.valueOf(setList.get(1).getV1()), Double.valueOf(setList.get(1).getV2()), Double.valueOf(setList.get(1).getV3()), Double.valueOf(setList.get(1).getV4()), Double.valueOf(setList.get(3).getV1()), Double.valueOf(setList.get(3).getV2()), Double.valueOf(setList.get(3).getV3()), Double.valueOf(setList.get(3).getV4()));
        List<SetUp> setUps = new ArrayList<>();
        setUps.add(setUp1);
        setUps.add(setUp2);
        return setUps;
    }

    @Override
    public void exportData(HttpServletResponse response, QhSynthesisExportParam param) {
        List<QhSynthesisExportVO> qhSynthesisExportVOS = assessRepository.getByParam(param);
        if ("0".equals(param.getAssessType())){
            ArrayList<String> list1 = new ArrayList<>();
            list1.add("years");
            ExcelUtil.hideColumn(QhSynthesisExportVO.class, list1, true);
            //条件(地震烈度 或 四个概率水准)
            if (param.getCategory().equals("0")) {
                ExcelUtil.setExcelAnnotationValue(QhSynthesisExportVO.class, "condition",
                        "name", "烈度");
            }
            if (param.getCategory().equals("1")) {
                ExcelUtil.setExcelAnnotationValue(QhSynthesisExportVO.class, "condition",
                        "name", "四个概率");
            }
            if (param.getCategory().equals("2")) {
                //地震影响场没有条件字段
                ArrayList<String> list2 = new ArrayList<>();
                list2.add("condition");
                ExcelUtil.hideColumn(QhSynthesisExportVO.class, list2, true);
            }
        }else if ("1".equals(param.getAssessType())){
            //隐藏经纬度范围字段
            ArrayList<String> list1 = new ArrayList<>();
            list1.add("condition");
            ExcelUtil.hideColumn(QhSynthesisExportVO.class, list1, true);
        }
        // String assessObj = param.getAssessObj();
        try {
            EasyPoiExcelUtil.exportExcel(qhSynthesisExportVOS, "综合指标确定评估风险区划", "风险区划", QhSynthesisExportVO.class,
                    "综合指标确定评估风险区划.xlsx", response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
